package com.prism.e4.rcp.listeners;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.custom.Bullet;
import org.eclipse.swt.custom.LineStyleEvent;
import org.eclipse.swt.custom.LineStyleListener;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GlyphMetrics;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;

public class PrismLineStyleListener implements LineStyleListener {

	private static final Color NUMBER_COLOR = new Color(Display.getCurrent(),
			new RGB(159, 182, 205));

	private static final Color KEYWORD_COLOR = new Color(Display.getCurrent(),
			new RGB(139, 58, 98));

	private static final Color DIGIT_COLOR = new Color(Display.getCurrent(),
			new RGB(139, 58, 98));

	private List<String> keywords = new ArrayList<String>();

	private StyledText textInstance;

	/**
	 * 
	 * @param text
	 *            creates new instance of PrismStyleListener, keywords found on
	 *            http://www.prismmodelchecker.org/manual/ThePRISMLanguage/
	 *            ModulesAndVariables
	 */
	public PrismLineStyleListener(StyledText text) {
		super();
		textInstance = text;
		keywords.add("A");
		keywords.add("bool");
		keywords.add("clock");
		keywords.add("const");
		keywords.add("ctmc");
		keywords.add("C");
		keywords.add("double");
		keywords.add("dtmc");
		keywords.add("E");
		keywords.add("endinit");
		keywords.add("endinvariant");
		keywords.add("endmodule");
		keywords.add("endrewards");
		keywords.add("endsystem");
		keywords.add("false");
		keywords.add("formula");
		keywords.add("filter");
		keywords.add("func");
		keywords.add("F");
		keywords.add("global");
		keywords.add("G");
		keywords.add("init");
		keywords.add("invariant");
		keywords.add("I");
		keywords.add("int");
		keywords.add("label");
		keywords.add("max");
		keywords.add("mdp");
		keywords.add("min");
		keywords.add("module");
		keywords.add("X");
		keywords.add("nondeterministic");
		keywords.add("Pmax");
		keywords.add("Pmin");
		keywords.add("P");
		keywords.add("probabilistic");
		keywords.add("prob");
		keywords.add("pta");
		keywords.add("rate");
		keywords.add("rewards");
		keywords.add("Rmax");
		keywords.add("Rmin");
		keywords.add("R");
		keywords.add("S");
		keywords.add("stochastic");
		keywords.add("system");
		keywords.add("true");
		keywords.add("U");
		keywords.add("W");
	}

	@Override
	public void lineGetStyle(LineStyleEvent event) {
		List<StyleRange> styles = new ArrayList<StyleRange>();
		int start = 0;
		int length = event.lineText.length();

		while (start < length) {
			if (Character.isLetter(event.lineText.charAt(start))) {
				StringBuffer buf = new StringBuffer();
				int i = start;
				for (; i < length
						&& Character.isLetter(event.lineText.charAt(i)); i++) {
					buf.append(event.lineText.charAt(i));
				}
				if (keywords.contains(buf.toString())) {
					styles.add(new StyleRange(event.lineOffset + start, i
							- start, KEYWORD_COLOR, null));
				}
				start = i;
			} else {
				start++;
			}
		}
		event.styles = (StyleRange[]) styles.toArray(new StyleRange[0]);

		event.bulletIndex = textInstance.getLineAtOffset(event.lineOffset);

		int maxLine = textInstance.getLineCount();
		int lineCountWidth = Math.max(String.valueOf(maxLine).length(), 3);

		StyleRange style = new StyleRange();
		style.metrics = new GlyphMetrics(0, 0, lineCountWidth * 8 + 5);
		Bullet bullet = new Bullet(ST.BULLET_NUMBER, style);
		textInstance.setLineBullet(0, textInstance.getLineCount(), null);
		textInstance.setLineBullet(0, textInstance.getLineCount(), bullet);
		event.bullet = bullet;
		style.foreground = NUMBER_COLOR;
	}
}
